package com.sunseen.capacitormachine.commumication.mqtt;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;

import com.hivemq.client.mqtt.MqttClient;
import com.hivemq.client.mqtt.datatypes.MqttQos;
import com.hivemq.client.mqtt.lifecycle.MqttClientConnectedContext;
import com.hivemq.client.mqtt.lifecycle.MqttClientDisconnectedContext;
import com.hivemq.client.mqtt.mqtt3.Mqtt3AsyncClient;
import com.sunseen.capacitormachine.common.MethodUtil;
import com.sunseen.capacitormachine.common.event.ConnectStateChangeEvent;
import com.sunseen.capacitormachine.commumication.mqtt.bean.OperatorData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.OperatorJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.bean.OvenTemperatureBatchData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.OvenTemperatureBatchJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.bean.PayloadBean;
import com.sunseen.capacitormachine.commumication.mqtt.bean.SurgeData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.SurgeDataJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.event.SendJsonObjEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.SurgeDataEvent;
import com.sunseen.capacitormachine.commumication.tcp.event.OvenTempEvent;
import com.sunseen.capacitormachine.data.DataUtil;
import com.sunseen.capacitormachine.data.ObjectBox;
import com.sunseen.capacitormachine.data.bean.CapacitorBean;
import com.sunseen.capacitormachine.modules.home.event.OperationInfoEvent;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

import io.objectbox.Box;

@SuppressLint("NewApi")
public class HiveMqttService extends Service {

    private static final String TAG = HiveMqttService.class.getSimpleName();
    private static final String serverUri = "192.168.0.100";//cloud_platform.test.sunseen.cc
    private static final int port = 1883;
    private static final int tryConnectTimeGap = 2000;
    private static final Handler handler = new Handler();

    private String userName = "6812B066";
    private String passWord = "38550743";
    private String topic = "/iot/6812B066/upload";

    private String clientId = "capacitor_machine_" + userName;

    private Mqtt3AsyncClient client;

    private Box<PayloadBean> payloadBeanBox;

    private void connect() {
        client.connectWith()
                .simpleAuth()
                .username(userName)
                .password(passWord.getBytes())
                .applySimpleAuth()
                .send();
    }

    private Runnable tryConnect = () -> connect();

    private int successCount = 0;

    @Override
    public void onCreate() {
        Log.e(TAG, "MqttService onCreate");
        EventBus.getDefault().register(this);
        super.onCreate();
        payloadBeanBox = ObjectBox.getBoxStore().boxFor(PayloadBean.class);
        client = MqttClient.builder()
                .useMqttVersion3()
                .identifier(clientId)
                .serverHost(serverUri)
                .serverPort(port)
                .addConnectedListener((@NotNull MqttClientConnectedContext context) -> {
                    handler.removeCallbacks(tryConnect);
                    EventBus.getDefault().post(new ConnectStateChangeEvent(2, false));
                    Log.e(TAG, "onConnectedListener mqtt connected");
                })
                .addDisconnectedListener((@NotNull MqttClientDisconnectedContext context) -> {
                    EventBus.getDefault().post(new ConnectStateChangeEvent(2, true));
                    handler.postDelayed(tryConnect, tryConnectTimeGap);
                    Log.e(TAG, "onDisconnectedListener mqtt disconnected");
                })
                .buildAsync();
        connect();
    }

    private void publish(byte[] payload) {
        client.publishWith()
                .topic(topic)
                .qos(MqttQos.AT_MOST_ONCE)
                .payload(payload)
                .send()
                .whenComplete((mqtt3Publish, throwable) -> {
                    if (throwable != null && !throwable.getMessage().isEmpty()) {
                        Log.e(TAG, "publish: failure " + throwable.getMessage());
                        //未上传的数据存到数据库中
                        payloadBeanBox.put(new PayloadBean(mqtt3Publish.getPayloadAsBytes()));
                    } else {
                        successCount++;
                        Log.e(TAG, "publish: success " + successCount);
                    }
                });
    }


    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onSendJsonObj(SendJsonObjEvent event) {
        publish(MethodUtil.Object2JSONBytes(event.getObj()));
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onSurgeDataEvent(SurgeDataEvent event) {
        String type = event.getSurgeType() == 1 ? "surgeData1" : "surgeData2";
        int time = (int) (System.currentTimeMillis() / 1000);
        int dataSize = event.getSurgeDatas().size();
        int[] datas = new int[dataSize];
        for (int i = 1; i <= dataSize; i++) {
            datas[i - 1] = event.getSurgeDatas().get(i);
        }
        SurgeData surgeData = new SurgeData(event.getUid(), event.getSurgeResult(),
                event.getBaseVoltage(), datas);
        SurgeDataJsonObj surgeDataJsonObj = new SurgeDataJsonObj(type, time, surgeData);
        publish(MethodUtil.Object2JSONBytes(surgeDataJsonObj));
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onOvenTempEvent(OvenTempEvent event) {
        List<CapacitorBean> capacitorBeanList = DataUtil.holderList
                .get(event.getHolderIndex()).getCapacitorList();
        List<String> stringList = new ArrayList<>();
        for (int i = 0; i < capacitorBeanList.size(); i++) {
            CapacitorBean capacitorBean = capacitorBeanList.get(i);
            if (!capacitorBean.isEmpty()) {
                stringList.add(capacitorBean.getUid());
            }
        }

        if (stringList.size() > 0) {
            OvenTemperatureBatchData data = new OvenTemperatureBatchData(event.getTemp(), stringList);
            OvenTemperatureBatchJsonObj jsonObj = new OvenTemperatureBatchJsonObj("", (int) (System.currentTimeMillis() / 1000), data);
            publish(MethodUtil.Object2JSONBytes(jsonObj));
        }
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onOperaionInfoEvent(OperationInfoEvent event) {
        OperatorData operatorData = new OperatorData(1, event.getInfo());
        OperatorJsonObj operatorJsonObj = new OperatorJsonObj("", System.currentTimeMillis()/1000, operatorData);
        publish(MethodUtil.Object2JSONBytes(operatorJsonObj));
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
        client.disconnect();
    }
}
